﻿// HSS.Interlink.ContextMenu.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.html)
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       ContextMenu.cs
// Author:     HSS\gbanta
// Created:    07/16/2011
// Modified:   07/22/2011
// ----------------------------------------------------------------------------
namespace HSS.Interlink
{
	#region Using Directives
	using System;
	using System.Collections.ObjectModel;
	using System.ComponentModel;
	using System.Windows;
	using System.Windows.Controls;
	using System.Windows.Controls.Primitives;
	using System.Windows.Input;
	using System.Windows.Media;
	#endregion

	#region ContextMenu
	/// <summary>
	/// A simple ContextMenu
	/// </summary>
	public sealed class ContextMenu
	{
		#region Fields
		Popup popup;
		ContextMenuView ctxView;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="owner">The ContextMenu owner.</param>
		public ContextMenu(Control owner)
		{
			this.Owner = owner;
			this.MenuItems = new ObservableCollection<ContextMenuItem>();
			this.ctxView = new ContextMenuView();
			this.ctxView.ItemsSource = this.MenuItems;
			ResourceDictionary rd = new ResourceDictionary()
			{
				Source = new Uri("/HSS.Interlink;component/Themes/ContextMenuStyle.xaml", UriKind.Relative)
			};
			ctxView.Resources.MergedDictionaries.Add(rd);
			ctxView.Template = (ControlTemplate)rd["ContextMenuTemplate"];
			ctxView.ItemTemplate = (DataTemplate)rd["ContextMenuItemTemplate"];
			ctxView.ItemContainerStyle = (Style)rd["ContextMenuItemContainerStyle"];
			ctxView.BorderThickness = new Thickness(0);
			ctxView.Background = new SolidColorBrush(Color.FromArgb(255, 239, 239, 239));
			ctxView.SelectionChanged += new SelectionChangedEventHandler(ctxView_SelectionChanged);
			ctxView.LostFocus += new RoutedEventHandler(ctxView_LostFocus);
			ctxView.LostMouseCapture += new MouseEventHandler(ctxView_LostMouseCapture);
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets the Owner of the ContextMenu
		/// </summary>
		public Control Owner { get; private set; }
		/// <summary>
		/// Gets the collection of MenuItems.
		/// </summary>
		public ObservableCollection<ContextMenuItem> MenuItems
		{
			get;
			private set;
		}
		#endregion

		#region Methods

		/// <summary>
		/// Present the ContextMenu
		/// </summary>
		/// <param name="currentMousePosition">The location in which the menu will be shown.</param>
		public void Show(Point currentMousePosition)
		{
			if (null != popup)
			{
				this.HidePopup();
				return;
			}
			popup = this.Initialize(currentMousePosition);
			popup.IsOpen = true;
		}

		internal void HidePopup()
		{
			popup.IsOpen = false;
			if (null != this.Owner)
				this.Owner.Focus();
		}
		Popup Initialize(Point currentMousePosition)
		{
			Popup popup = new Popup();
			Grid popupGrid = new Grid();
			Canvas popupCanvas = new Canvas();
			Border border = new Border()
			{
				HorizontalAlignment = HorizontalAlignment.Left,
				VerticalAlignment = VerticalAlignment.Top,
				CornerRadius = new CornerRadius(2),
				BorderThickness = new Thickness(1),
				BorderBrush = new SolidColorBrush(Colors.Gray),
				Margin = new Thickness(currentMousePosition.X, currentMousePosition.Y, 0, 0),
				Child = ctxView
			};
			popup.Child = popupGrid;
			popupCanvas.MouseLeftButtonDown += (sender, e) => { HidePopup(); };
			popupCanvas.MouseRightButtonDown += (sender, e) => { e.Handled = true; HidePopup(); };
			popupCanvas.Background = new SolidColorBrush(Colors.Transparent);
			popupGrid.Children.Add(popupCanvas);
			popupGrid.Children.Add(border);

			popupGrid.Width = Owner.ActualWidth;
			popupGrid.Height = Owner.ActualHeight;
			popupCanvas.Width = popupGrid.Width;
			popupCanvas.Height = popupGrid.Height;
			return popup;
		}

		#endregion

		#region Event Handlers
		void ctxView_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			this.HidePopup();
			ContextMenuItem item = this.ctxView.SelectedItem as ContextMenuItem;
			if (null != item)
				item.FireClickAndExecute();
		}
		void ctxView_LostFocus(object sender, RoutedEventArgs e)
		{
			this.HidePopup();
		}
		void ctxView_LostMouseCapture(object sender, MouseEventArgs e)
		{
			this.HidePopup();
		}
		#endregion
	}
	#endregion

	#region ContextMenuItem
	/// <summary>
	/// A simple ContextMenuItem base class.
	/// </summary>
	public abstract class ContextMenuItem : INotifyPropertyChanged
	{
		#region Events

		#region INotifyPropertyChanged Members
		/// <summary>
		/// Occurs when a Property is changed.
		/// </summary>
		public event PropertyChangedEventHandler PropertyChanged;
		private void OnPropertyChanged(string prop)
		{
			var handler = this.PropertyChanged;
			if (null == handler)
				return;
			handler(this, new PropertyChangedEventArgs(prop));
		}
		#endregion

		#endregion

		#region Constructors
		/// <summary>
		/// Constructor
		/// </summary>
		public ContextMenuItem()
		{
			this.Execute = this.DefaultExecute;
			this.CanExecute = this.DefaultCanExecute;
		}
		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the Text to display for this MenuItem.
		/// </summary>
		public string Text
		{
			get { return _text; }
			set
			{
				_text = value;
				OnPropertyChanged("Text");
			}
		} string _text;
		/// <summary>
		/// Gets or sets the image for this Menu Item
		/// </summary>
		public ImageSource Image
		{
			get;
			set;
		}
		/// <summary>
		/// Gets or sets the Action to perform.
		/// </summary>
		public Action Execute
		{
			get;
			set;
		}
		/// <summary>
		/// Gets or sets the CanExecute Func'bool
		/// </summary>
		public Func<bool> CanExecute
		{
			get;
			set;
		}
		#endregion

		#region Overrides
		/// <summary>
		/// Returns the Text
		/// </summary>
		/// <returns>The Text</returns>
		public override string ToString()
		{
			return "[" + this.GetType().Name + "] " + this.Text;
		}
		#endregion

		#region Methods
		internal void FireClickAndExecute()
		{
			if (null != this.Execute)
				this.Execute();
		}
		bool DefaultCanExecute()
		{
			return true;
		}
		void DefaultExecute()
		{
		}
		#endregion
	}
	#endregion

	#region TextContextMenuItem
	/// <summary>
	/// TextContextMenuItem
	/// </summary>
	public sealed class TextContextMenuItem : ContextMenuItem
	{
		/// <summary>
		/// Constructor
		/// </summary>
		public TextContextMenuItem()
		{

		}
	}
	#endregion
}